#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
行为模拟模块

模拟真实用户的浏览行为，提高反爬效果。
"""

import asyncio
import random
import logging
from datetime import datetime, timedelta
from typing import Dict, List, Optional, Tuple
import json
import time

class BehaviorSimulator:
    """行为模拟器"""
    
    def __init__(self, config: Dict = None):
        self.logger = logging.getLogger(__name__)
        
        # 默认配置
        self.config = {
            "mouse_movement_enabled": True,
            "scroll_simulation": True,
            "typing_delays": True,
            "page_focus_simulation": True,
            "tab_switching": False,
            "cookie_management": True
        }
        
        if config:
            self.config.update(config)
        
        # 用户行为模式
        self.behavior_patterns = {
            "active_user": {
                "scroll_frequency": 0.8,
                "click_rate": 0.6,
                "reading_time_multiplier": 1.2
            },
            "casual_user": {
                "scroll_frequency": 0.5,
                "click_rate": 0.3,
                "reading_time_multiplier": 0.8
            },
            "power_user": {
                "scroll_frequency": 1.0,
                "click_rate": 0.9,
                "reading_time_multiplier": 0.6
            }
        }
        
        # 当前会话状态
        self.session_state = {
            "user_pattern": "casual_user",
            "session_start": datetime.now(),
            "pages_visited": 0,
            "total_scroll_distance": 0,
            "interaction_count": 0
        }
        
        self.logger.info("行为模拟器初始化完成")
    
    async def simulate_page_visit(self, url: str) -> Dict:
        """
        模拟页面访问行为
        
        Args:
            url: 访问的URL
            
        Returns:
            Dict: 模拟的行为数据
        """
        visit_start = time.time()
        
        # 模拟页面加载等待
        await self.simulate_page_load_wait()
        
        # 模拟滚动行为
        scroll_actions = await self.simulate_scrolling()
        
        # 模拟停留时间
        reading_time = await self.simulate_reading_time(url)
        
        # 模拟交互行为
        interactions = await self.simulate_interactions()
        
        # 更新会话状态
        self.session_state["pages_visited"] += 1
        self.session_state["interaction_count"] += len(interactions)
        
        visit_duration = time.time() - visit_start
        
        return {
            "url": url,
            "visit_duration": visit_duration,
            "reading_time": reading_time,
            "scroll_actions": scroll_actions,
            "interactions": interactions,
            "timestamp": datetime.now().isoformat()
        }
    
    async def simulate_page_load_wait(self):
        """模拟页面加载等待"""
        # 模拟网络延迟和页面渲染时间
        load_time = random.uniform(0.5, 2.0)  # 0.5-2秒加载时间
        await asyncio.sleep(load_time)
        
        # 额外的DOM加载等待
        dom_wait = random.uniform(0.1, 0.5)
        await asyncio.sleep(dom_wait)
    
    async def simulate_scrolling(self) -> List[Dict]:
        """模拟滚动行为"""
        pattern = self.behavior_patterns[self.session_state["user_pattern"]]
        scroll_frequency = pattern["scroll_frequency"]
        
        scroll_actions = []
        
        if random.random() < scroll_frequency:
            # 决定滚动次数
            scroll_count = random.randint(2, 8)
            
            for i in range(scroll_count):
                # 滚动距离
                scroll_distance = random.randint(100, 800)
                
                # 滚动方向（偶尔向上滚动）
                direction = "down" if random.random() > 0.1 else "up"
                if direction == "up":
                    scroll_distance = min(scroll_distance, 200)
                
                # 滚动速度（模拟不同的滚动习惯）
                scroll_speed = random.choice(["slow", "medium", "fast"])
                speed_multiplier = {"slow": 1.5, "medium": 1.0, "fast": 0.6}[scroll_speed]
                
                scroll_duration = (scroll_distance / 500) * speed_multiplier
                
                scroll_actions.append({
                    "type": "scroll",
                    "direction": direction,
                    "distance": scroll_distance,
                    "duration": scroll_duration,
                    "speed": scroll_speed
                })
                
                # 滚动间隔
                scroll_pause = random.uniform(0.5, 3.0)
                await asyncio.sleep(scroll_pause)
                
                # 偶尔停下来"阅读"
                if random.random() < 0.3:
                    reading_pause = random.uniform(2.0, 8.0)
                    await asyncio.sleep(reading_pause)
        
        return scroll_actions
    
    async def simulate_reading_time(self, url: str) -> float:
        """模拟阅读时间"""
        pattern = self.behavior_patterns[self.session_state["user_pattern"]]
        multiplier = pattern["reading_time_multiplier"]
        
        # 基础阅读时间（根据内容类型调整）
        if "video" in url.lower():
            base_time = random.uniform(30, 120)  # 视频页面停留更久
        elif "search" in url.lower():
            base_time = random.uniform(10, 30)   # 搜索页面相对较短
        else:
            base_time = random.uniform(15, 60)   # 普通页面
        
        # 应用用户模式乘数
        reading_time = base_time * multiplier
        
        # 添加随机变化
        reading_time *= random.uniform(0.7, 1.5)
        
        # 模拟阅读过程中的暂停
        total_pause_time = 0
        pause_count = random.randint(1, 4)
        
        for _ in range(pause_count):
            pause_duration = reading_time / pause_count
            await asyncio.sleep(pause_duration)
            
            # 偶尔有较长的暂停（思考、分心等）
            if random.random() < 0.2:
                extra_pause = random.uniform(3.0, 10.0)
                await asyncio.sleep(extra_pause)
                total_pause_time += extra_pause
        
        return reading_time + total_pause_time
    
    async def simulate_interactions(self) -> List[Dict]:
        """模拟交互行为"""
        pattern = self.behavior_patterns[self.session_state["user_pattern"]]
        click_rate = pattern["click_rate"]
        
        interactions = []
        
        # 模拟点击行为
        if random.random() < click_rate:
            click_count = random.randint(1, 3)
            
            for _ in range(click_count):
                # 点击类型
                click_types = ["like", "comment", "share", "follow", "view_profile"]
                click_type = random.choice(click_types)
                
                # 点击位置（模拟）
                click_position = {
                    "x": random.randint(100, 1200),
                    "y": random.randint(200, 800)
                }
                
                # 点击延迟（鼠标移动到点击的时间）
                move_delay = random.uniform(0.2, 1.0)
                await asyncio.sleep(move_delay)
                
                interactions.append({
                    "type": "click",
                    "element": click_type,
                    "position": click_position,
                    "timestamp": datetime.now().isoformat()
                })
                
                # 点击后的等待时间
                post_click_delay = random.uniform(0.5, 2.0)
                await asyncio.sleep(post_click_delay)
        
        # 模拟键盘输入（搜索、评论等）
        if random.random() < 0.1:  # 较少的输入行为
            input_simulation = await self.simulate_typing()
            interactions.append(input_simulation)
        
        return interactions
    
    async def simulate_typing(self) -> Dict:
        """模拟打字行为"""
        # 模拟输入内容
        sample_inputs = [
            "不错", "很好", "赞", "哈哈", "👍", "好看",
            "这个怎么样", "在哪里", "多少钱", "什么时候"
        ]
        
        input_text = random.choice(sample_inputs)
        
        # 模拟打字速度（每个字符的间隔）
        typing_speed = random.uniform(0.1, 0.3)  # 秒/字符
        
        typing_start = time.time()
        
        # 模拟逐字符输入
        for char in input_text:
            await asyncio.sleep(typing_speed)
            
            # 偶尔有打字错误和修正
            if random.random() < 0.05:
                # 模拟删除和重新输入
                await asyncio.sleep(0.5)  # 发现错误的停顿
                await asyncio.sleep(0.2)  # 删除时间
                await asyncio.sleep(typing_speed)  # 重新输入
        
        typing_duration = time.time() - typing_start
        
        return {
            "type": "typing",
            "text": input_text,
            "duration": typing_duration,
            "speed": len(input_text) / typing_duration,
            "timestamp": datetime.now().isoformat()
        }
    
    async def simulate_session_break(self):
        """模拟会话中断（休息、离开等）"""
        break_types = {
            "short_break": (5, 30),      # 短暂离开：5-30秒
            "coffee_break": (60, 300),   # 咖啡时间：1-5分钟
            "lunch_break": (900, 1800),  # 午餐时间：15-30分钟
            "distraction": (10, 120)     # 分心：10秒-2分钟
        }
        
        # 根据时间和会话状态选择中断类型
        current_hour = datetime.now().hour
        session_duration = (datetime.now() - self.session_state["session_start"]).total_seconds()
        
        if 12 <= current_hour <= 13:  # 午餐时间
            break_type = "lunch_break" if random.random() < 0.3 else "short_break"
        elif session_duration > 1800:  # 会话超过30分钟
            break_type = random.choice(["coffee_break", "short_break", "distraction"])
        else:
            break_type = random.choice(["short_break", "distraction"])
        
        min_time, max_time = break_types[break_type]
        break_duration = random.uniform(min_time, max_time)
        
        self.logger.debug(f"模拟会话中断: {break_type}, 时长: {break_duration:.1f}秒")
        await asyncio.sleep(break_duration)
        
        return {
            "type": "session_break",
            "break_type": break_type,
            "duration": break_duration,
            "timestamp": datetime.now().isoformat()
        }
    
    def generate_realistic_headers(self, base_headers: Dict = None) -> Dict:
        """生成真实的浏览器请求头"""
        # 常见的User-Agent列表
        user_agents = [
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36",
            "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/120.0",
            "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.1 Safari/605.1.15"
        ]
        
        # 基础请求头
        headers = {
            "User-Agent": random.choice(user_agents),
            "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
            "Accept-Language": random.choice([
                "zh-CN,zh;q=0.9,en;q=0.8",
                "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2",
                "zh-CN,zh;q=0.9"
            ]),
            "Accept-Encoding": "gzip, deflate, br",
            "DNT": random.choice(["1", "0"]),
            "Connection": "keep-alive",
            "Upgrade-Insecure-Requests": "1",
            "Cache-Control": random.choice(["no-cache", "max-age=0", "no-store"])
        }
        
        # 随机添加一些可选头部
        optional_headers = {
            "Sec-Fetch-Dest": random.choice(["document", "empty"]),
            "Sec-Fetch-Mode": random.choice(["navigate", "cors"]),
            "Sec-Fetch-Site": random.choice(["none", "same-origin", "cross-site"]),
            "Sec-Fetch-User": "?1"
        }
        
        # 随机添加可选头部
        for key, value in optional_headers.items():
            if random.random() > 0.3:  # 70%概率添加
                headers[key] = value
        
        # 合并基础头部
        if base_headers:
            headers.update(base_headers)
        
        return headers
    
    def simulate_browser_fingerprint(self) -> Dict:
        """模拟浏览器指纹"""
        fingerprint = {
            "screen_resolution": random.choice([
                "1920x1080", "1366x768", "1440x900", "1536x864", "1280x720"
            ]),
            "color_depth": random.choice([24, 32]),
            "timezone": random.choice([
                "Asia/Shanghai", "Asia/Beijing", "UTC+8"
            ]),
            "language": random.choice(["zh-CN", "zh", "zh-TW"]),
            "platform": random.choice(["Win32", "MacIntel", "Linux x86_64"]),
            "cookie_enabled": True,
            "online": True,
            "webgl_vendor": random.choice([
                "Google Inc.", "Intel Inc.", "NVIDIA Corporation"
            ])
        }
        
        return fingerprint
    
    def get_behavior_stats(self) -> Dict:
        """获取行为统计"""
        session_duration = (datetime.now() - self.session_state["session_start"]).total_seconds()
        
        return {
            "session_duration": session_duration,
            "pages_visited": self.session_state["pages_visited"],
            "total_interactions": self.session_state["interaction_count"],
            "avg_interactions_per_page": self.session_state["interaction_count"] / max(1, self.session_state["pages_visited"]),
            "user_pattern": self.session_state["user_pattern"],
            "session_start": self.session_state["session_start"].isoformat()
        }
    
    def switch_user_pattern(self, pattern: str = None):
        """切换用户行为模式"""
        if pattern and pattern in self.behavior_patterns:
            self.session_state["user_pattern"] = pattern
        else:
            # 随机切换模式
            patterns = list(self.behavior_patterns.keys())
            current_pattern = self.session_state["user_pattern"]
            patterns.remove(current_pattern)
            self.session_state["user_pattern"] = random.choice(patterns)
        
        self.logger.info(f"切换到用户模式: {self.session_state['user_pattern']}")
    
    async def simulate_multi_tab_behavior(self):
        """模拟多标签页行为"""
        if not self.config["tab_switching"]:
            return
        
        # 模拟打开新标签页
        if random.random() < 0.2:
            tab_switch_delay = random.uniform(1.0, 5.0)
            await asyncio.sleep(tab_switch_delay)
            
            # 模拟在其他标签页的活动
            other_tab_duration = random.uniform(10.0, 60.0)
            await asyncio.sleep(other_tab_duration)
            
            # 返回原标签页
            return_delay = random.uniform(0.5, 2.0)
            await asyncio.sleep(return_delay)
    
    def reset_session(self):
        """重置会话状态"""
        self.session_state = {
            "user_pattern": random.choice(list(self.behavior_patterns.keys())),
            "session_start": datetime.now(),
            "pages_visited": 0,
            "total_scroll_distance": 0,
            "interaction_count": 0
        }
        
        self.logger.info(f"会话已重置，用户模式: {self.session_state['user_pattern']}")